# coding: utf-8
"""
author: danqing
date: 2022-09-29
desc: 脚本中常用的函数
"""
import json
import os
import time
import re
import requests
from eval_lib.common.ssh import SSHPool
from common import const
from config import conf
from eval_lib.common.logger import get_logger
from common.utils import ssh_pool_default

log = get_logger()


class DeployUtils(object):

    def __init__(
        self, df_mgt_ip=None, df_server_controller_port=None,
        df_server_query_port=None, df_server_image_tag=None,
        df_agent_image_tag=None, ssh_pool=ssh_pool_default
    ):
        self.df_mgt_ip = df_mgt_ip
        self.df_server_controller_port = df_server_controller_port
        self.df_server_query_port = df_server_query_port
        self.df_server_image_tag = df_server_image_tag
        self.df_agent_image_tag = df_agent_image_tag
        self._ssh_pool: SSHPool = ssh_pool

    def exec_cmd(self, ssh, cmd="", err_assert=False):
        if cmd == "":
            log.error("The command is None")
            assert False
        log.info("exec_cmd::cmd ==> {}".format(cmd))
        stdin, stdout, stderr = ssh.exec_command(cmd)
        logs = stdout.readlines()
        log.info("exec_cmd::logs ==> {}".format(logs))
        err = stderr.readlines()
        if err:
            log.error(f"exec_cmd::err ==> {err}")
            assert err_assert == False
        return logs, err

    def replace_registry_public_to_private(self, filename):
        if not filename:
            return
        ssh = self._ssh_pool.get(self.df_mgt_ip)
        cmd = f"sed -i 's/registry.cn-beijing.aliyuncs.com/registry-vpc.cn-beijing.aliyuncs.com/g' {filename}"
        _, stdout, stderr = ssh.exec_command(cmd)
        err = stderr.readlines()
        if err:
            log.error(f"Replace Registery Error: {err}")

    def get_query_port(self):
        '''Login to the deepflow by SSH, Deepflow gets query_port, parameter:
        self.df_mgt_ip; The ip of deepflow
        username; login username
        password; login password
        ssh_port; port
        '''
        ssh = self._ssh_pool.get(self.df_mgt_ip)
        query_api_port = None
        loop_num = 100
        while loop_num:
            try:
                log.info("get querier port")
                stdin, stdout, stderr = ssh.exec_command(
                    '''kubectl get svc -n deepflow|grep -o "20416:[0-9]*" | cut -d ":" -f 2
                ''', timeout=10
                )
                out = stdout.readlines()
                log.info(out)
                query_api_port = out[0].strip()
                log.info(f"query_port :{query_api_port}")
                if query_api_port:
                    break
            except Exception as e:
                log.error(f"get port error:{e}")
                time.sleep(3)
            loop_num -= 1
        self.df_server_query_port = query_api_port
        return query_api_port

    def get_controller_port(self):
        '''Login to the deepflow by SSH, Deepflow gets controller_port, parameter:
        self.df_mgt_ip; The ip of deepflow
        username; login username
        password; login password
        ssh_port; port
        '''
        ssh = self._ssh_pool.get(self.df_mgt_ip)
        controller_api_port = None
        loop_num = 100
        while loop_num:
            try:
                log.info("get controller port")
                stdin, stdout, stderr = ssh.exec_command(
                    '''kubectl get svc -n deepflow|grep -o "20417:[0-9]*" | cut -d ":" -f 2
                ''', timeout=10
                )
                controller_api_port = stdout.readlines()[0].strip()
                log.info(f"controller_port :{controller_api_port}")
                if controller_api_port:
                    break
            except Exception as e:
                log.error(f"get port error:{e}")
                time.sleep(3)
            loop_num -= 1
        self.df_server_controller_port = controller_api_port
        return controller_api_port

    def add_deepflow_server_dns(
        self, dns_server=const.ext_dns_server
    ):
        '''add dns server for deepflow_server, parameter;
        dns_server; default, type is string
        username; default, type is string
        password; default, type is string
        ssh_port; default, type is string
        self.df_mgt_ip; default, type is string
        '''
        ssh = self._ssh_pool.get(self.df_mgt_ip)
        stdin, stdout, stderr = ssh.exec_command(
            '''kubectl get deployment deepflow-server -n deepflow -o yaml > deepflow-server-dns.yaml && \
                                                    sed -i "/dnsPolicy: ClusterFirst/a\      dnsConfig:" deepflow-server-dns.yaml && \
                                                    sed -i "/      dnsConfig:/a\         nameservers:" deepflow-server-dns.yaml && \
                                                    sed -i "/         nameservers:/a\         - {}" deepflow-server-dns.yaml &&\
                                                    kubectl apply -f deepflow-server-dns.yaml'''
            .format(dns_server)
        )
        logs = stdout.readlines()
        log.info(logs)
        err = stderr.readlines()
        if err:
            log.error(f"dns add error: {err}")
        return

    def install_deepflow_ctl(
        self
    ):
        cmds = [
            "curl -o /usr/bin/deepflow-ctl https://deepflow-ce.oss-cn-beijing.aliyuncs.com/bin/ctl/stable/linux/$(arch | sed 's|x86_64|amd64|' | sed 's|aarch64|arm64|')/deepflow-ctl",
            "chmod a+x /usr/bin/deepflow-ctl",
            "deepflow_server_pod_ip=$(kubectl -n deepflow get pods -o wide | grep deepflow-server | awk '{print $6}')",
            "deepflow-ctl -i $deepflow_server_pod_ip ingester profiler on"
        ]
        log.info("start install deepflow-ctl")
        ssh = self._ssh_pool.get(self.df_mgt_ip)
        for cmd in cmds:
            log.info(f"exec cmd: {cmd}")
            _, stdout, stderr = ssh.exec_command(cmd)
            err = stderr.readlines()
            if err:
                log.error(err)
            log.info(stdout.readlines())
        return

    def check_aliyun_cloud_isexist(self):
        '''determine whether Aliyun Cloud platform exists, parameter;
        self.df_mgt_ip; default, type is string
        '''
        result = False
        domain_url = 'http://' + self.df_mgt_ip + ':' + str(
            self.df_server_controller_port
        ) + '/v2/domains'
        loop_num = 30
        while loop_num:
            try:
                res = requests.get(url=domain_url)
                if res.status_code == 200:
                    res_json = res.json()['DATA']
                    for i in res_json:
                        if i['TYPE'] == 9:
                            result = True
                            log.info('aliyun cloud is exist')
                            break
                        else:
                            log.info("aliyun cloud doesn't exist")
                break
            except Exception as e:
                loop_num -= 1
                log.error(f"get domain error: {e}")
                time.sleep(10)
        return result

    def check_aliyun_cloud_status(
        self, cloud_name=const.ali_name_default
    ):
        '''check aliyun cloud status, parameter;
        cloud_name, required, type is string
        self.df_mgt_ip, default, type is string
        '''
        result = False
        loop_num = 120
        while loop_num:
            try:
                domain_url = 'http://' + self.df_mgt_ip + ':' + str(
                    self.df_server_controller_port
                ) + '/v2/domains'
                res = requests.get(url=domain_url)
                if res.status_code == 200:
                    res_json = res.json()['DATA']
                    log.info(f'aliyun domain info: {res_json}')
                    for i in res_json:
                        if i['NAME'] == cloud_name and i['TYPE'] == 9 and i[
                            'ENABLED'] == 1 and len(i['SYNCED_AT']) > 0:
                            if i['STATE'] == 1:
                                log.info(
                                    'aliyun cloud platform status is normal'
                                )
                                result = True
                                break
                            if i['STATE'] == 4:
                                if "no vtap report cluster id:" in i[
                                    'ERROR_MSG']:
                                    log.warning(
                                        f"aliyun error_msg: {i['ERROR_MSG']}"
                                    )
                                    log.info(
                                        'aliyun cloud platform status is normal'
                                    )
                                    result = True
                                    break
                if result:
                    break
                else:
                    log.info('wait for aliyun cloud sync, about 10s')
                    time.sleep(10)
                    loop_num -= 1
            except Exception as e:
                log.error(f'aliyun cloud sync error: {e}')
                time.sleep(10)
                loop_num -= 1
        return result

    def add_aliyun_cloud_platform(
        self, cloud_name=const.ali_name_default
    ):
        '''add aliyun cloud platform, parameter;
        cloud_name, default, type is string
        '''
        result = False
        loop_num = 30
        while loop_num:
            try:
                domain_url = 'http://' + self.df_mgt_ip + ':' + str(
                    self.df_server_controller_port
                ) + '/v1/domains/'
                header = {'content-type': 'application/json'}
                data = {
                    "TYPE": 9,
                    "NAME": "{}".format(cloud_name),
                    "ICON_ID": 8,
                    "CONFIG": {
                        "region_uuid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
                        "controller_ip": "{}".format(self.df_mgt_ip),
                        "secret_id": "{}".format(
                            os.getenv('ALICLOUD_ACCESS_KEY')
                        ),
                        "secret_key": "{}".format(
                            os.getenv('ALICLOUD_SECRET_KEY')
                        ),
                        "include_regions": "华北2（北京）",
                        "exclude_regions": "华南3（广州）,欧洲中部 1 (法兰克福),中东东部 1 (迪拜),英国 (伦敦),美国西部 1 (硅谷),美国东部 1 (弗吉尼亚),亚太南部 1 (孟买),亚太东南 3 (吉隆坡),亚太东南 5 (雅加达),亚太东南 2 (悉尼),亚太东南 1 (新加坡),亚太东北 1 (东京),香港,华北6（乌兰察布）,华东5（南京-本地地域）",
                        "k8s_confs": ""
                    }
                }
                data = json.dumps(data)
                res = requests.post(url=domain_url, headers=header, data=data)
                if res.status_code == 200:
                    log.info('add aliyun cloud successfully')
                    result = True
                    break
                else:
                    loop_num -= 1
                    log.info(f'add aliyun cloud failed, status_code err: {res}')
                    log.info(res.json())
                    time.sleep(10)
            except Exception as err:
                log.error(
                    'add aliyun cloud failed, log info is {}'.format(err)
                )
                time.sleep(10)
                loop_num -= 1
        return result

    def delete_aliyun_cloud_platform(self):
        '''delete aliyun cloud platform, parameter;
        self.df_mgt_ip, default, type is string
        '''
        try:
            domain_url = url.protocol + self.df_mgt_ip + ':' + str(
                self.df_server_controller_port
            ) + url.domains_api_prefix
            lcuuid = ''
            res = requests.get(url=domain_url)
            if res.status_code == 200:
                res_json = res.json()['DATA']
                for i in res_json:
                    if i['TYPE'] == 9:
                        lcuuid = i['LCUUID']
                        break
            delete_domain_url = url.protocol + self.df_mgt_ip + ':' + str(
                self.df_server_controller_port
            ) + url.v1_domains_api_prefix + '{}/'.format(lcuuid)
            res = requests.delete(url=delete_domain_url)
            if res.status_code == 200:
                log.info('delete aliyun cloud successfully')
        except Exception as err:
            log.error('delete aliyun cloud failed, log info is {}'.format(err))

    def check_pod_running(
        self, pod_name=None, namespace="deepflow", ip=None, timeout=3 * 60
    ):
        if not ip:
            ip = self.df_mgt_ip
        cmd = "kubectl get pods -n {namespace}"
        if not pod_name:
            cmd = f"{cmd}|grep {pod_name}"
        ssh = self._ssh_pool.get(ip)

        while timeout:
            log.info(
                f'Wait for {namespace} pod {pod_name} status to be normal, timeout is {timeout}'
            )
            timeout -= 10
            time.sleep(10)
            stdin, stdout, stderr = ssh.exec_command(cmd)
            logs = stdout.readlines()
            res = True
            for k in logs[1:]:
                log.info("get pod ========= > {}".format(k))
                if 'Running' not in k.split()[2] or '0/' in k.split()[1]:
                    res = False
                    break
            if res == True:
                log.info(f'{namespace} pod {pod_name} is normal')
                return True
        log.error(f"{namespace} pod {pod_name} is not running \n {logs}")
        return False

    def add_aliyun_dns(
        self, vtaps_mgt_ip
    ):
        ssh = self._ssh_pool.get(vtaps_mgt_ip)
        cmd = f'''echo "nameserver {const.ali_dns_ip}" > /etc/resolv.conf'''
        self.exec_cmd(ssh=ssh, cmd=cmd, err_assert=True)